package com.airspyar;

import java.util.Vector;

import org.codehaus.jackson.map.ObjectMapper;

import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class PlaneSelector extends ThreadExtended{
	
	public final static int PLANE_SELECTED_MESSAGE=1;
	public final static int NOTHING_SELECTED_MESSAGE=2;
	private final static float MAX_ANGLE=17;
	private final static int DOWNLOAD_INTERVAL=3000;
	private final static int NULL_STATES_LIMIT=3;
	
	private final ObserverDataHolder observerDataHolder;
	private final PlanesDataProvider planesDataProvider;
	private final Handler handler;
	
	private final static ObjectMapper mapper=new ObjectMapper();
	
	private final Timer timer;
	
	private int nullCounter=0;
	private Bitmap lastBitmap=null;
	private FlightState lastState=null;
	
	public PlaneSelector(Handler handler, ObserverDataHolder observerDataHolder, PlanesDataProvider planesDataProvider){
		this.handler=handler;
		this.observerDataHolder=observerDataHolder;
		this.planesDataProvider=planesDataProvider;
		this.timer=new Timer(DOWNLOAD_INTERVAL);
	}

	private static DetailedFlightState getDetailedState(FlightState state) throws Exception{
		String data=Utils.fetchPage("http://www.flightradar24.com/FlightDataService.php?hex="+state.getHex()+"&callsign="+state.getCallsign(), 4000, 5000);

		JSONFlightState detailedInfo = mapper.readValue(data, JSONFlightState.class);
		
		return new DetailedFlightState(state, detailedInfo);
	}
	
	@Override
	public void setPaused(boolean p){
		if(!p)
			nullCounter=NULL_STATES_LIMIT;
		
		super.setPaused(p);
	}
	
	protected void loop(){
		FlightState state=choosePlane();
			
		if(state==null){
			nullCounter++;
			if(nullCounter>NULL_STATES_LIMIT && lastState!=null){
					handler.sendEmptyMessage(NOTHING_SELECTED_MESSAGE);
					lastState=null;
			}
			return;
		}
		nullCounter=0;

		if(state.isTheSameFlight(lastState) && !timer.intervalElapsed())
			return;
			
		Message msg=new Message();
		msg.what=PLANE_SELECTED_MESSAGE;
			
		try{
			DetailedFlightState detailedState=getDetailedState(state);
			if(state.isTheSameFlight(lastState)){
				detailedState.setBitmap(lastBitmap);
			}
			else{
				detailedState.loadBitmap();
				lastBitmap=detailedState.getBitmap();
			}
			msg.obj=detailedState;
		}catch(Exception e){
			if(AirSpyActivity.LOG_ERROR)
				Log.e("PlaneSelector exception", "Could not get detailed data: "+e.getMessage());
			return;
		}
			
		lastState=state;

		if(!isKilled() && !isPaused())
			handler.sendMessage(msg);

	}	

	
	private FlightState choosePlane(){
		if(!observerDataHolder.isInitialized())
			return null;

		SimpleLocation observerLocation=observerDataHolder.getSimpleLocation();
		Vector3d orientation=observerDataHolder.getOrientationVector();
		
		Vector<FlightState> planes=planesDataProvider.getPlanes();
		if(planes==null || planes.isEmpty()){
			if(AirSpyActivity.LOG_WARN) 
				Log.w("PlaneSelector warning", "No planes found");
			return null;
		}
		
		if(observerLocation==null){
			if(AirSpyActivity.LOG_ERROR) 
				Log.e("PlaneSelector error", "Could not obtain observer's location");
			return null;
		}
		
		if(orientation==null){
			if(AirSpyActivity.LOG_ERROR) 
				Log.e("PlaneSelector error", "Could not obtain device's orientation");
			return null;
		}
		
		float bestMatch=MAX_ANGLE;
		FlightState bestMatchingPlane=null;
		
		for(FlightState plane : planes){			
			Vector3d distVector=plane.getUpdatedDistVector();
			if(distVector.lenght()>planesDataProvider.getVisibilityDistance())
				continue;
			
			float angle=Utils.calculateAngle(orientation, distVector);
			angle=(float)Math.abs(Math.toDegrees(angle));
			angle*=1+0.25f*((float)plane.getDistance()/PlanesDataProvider.VISIBILITY_MAX);
			
			if(angle<bestMatch){
				bestMatchingPlane=plane;
				bestMatch=angle;
			}
		}
		
		return bestMatchingPlane;
	}
}
